﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LightCAD.MathLib
{

    public class ListEx<T> : List<T>
    {
        public ListEx()
        {
        }
        public ListEx(int capacity)
            : base(capacity)
        {
            for (var i = 0; i < capacity; i++)
                this.Add(default(T));
        }

        public new T this[int index]
        {
            get
            {
                if (index < 0 || index >= this.Count)
                {
                    return default(T);
                }
                else
                    return base[index];
            }
            set
            {
                if (index >= this.Count)
                {
                    for (var i = 0; i < index - this.Count + 1; i++)
                    {
                        this.Add(default(T));
                    }
                }
                base[index] = value;
            }
        }
        public T Get(int index)
        {
            if (index < 0 || index >= this.Count)
                return default(T);
            else
                return this[index];
        }
        public void Set(int index, T value)
        {
            if (index >= this.Count)
            {
                for (var i = 0; i < index - this.Count + 1; i++)
                {
                    this.Add(default(T));
                }
            }
            this[index] = value;
        }

        public int Length
        {
            get { return this.Count; }
            set
            {
                if (value == 0)
                    this.Clear();
                else
                {
                    var len = Length;
                    if (value > len)
                    {
                        for (int i = len; i < value; i++)
                        {
                            this.Add(default);
                        }
                    }
                    else if (value < len)
                    {
                        for (int i = len - 1; i >= value; i--)
                        {
                            this.RemoveAt(i);
                        }
                    }
                    //throw new Exception("can not set length in C#."); 
                }
            }
        }
        public T Find(Func<T, bool> func)
        {
            foreach (var item in this)
            {
                if (func(item))
                {
                    return item;
                }
            }
            return default(T);
        }
        public void ForEach(Action<T, int> action)
        {
            for (var i = 0; i < this.Count; i++)
            {
                action(this[i], i);
            }
        }
        public void ForEach(Action<T> action)
        {
            for (var i = 0; i < this.Count; i++)
            {
                action(this[i]);
            }
        }
        public ListEx<T> Push(params T[] items)
        {
            for (var i = 0; i < items.Length; i++)
                this.Add(items[i]);
            return this;
        }
        public ListEx<T> PushNoRepeat(params T[] items)
        {
            for (var i = 0; i < items.Length; i++)
                if (!this.Contains(items[i]))
                    this.Add(items[i]);
            return this;
        }
        public ListEx<T> PushOverrideSame(params T[] items)
        {
            for (var i = 0; i < items.Length; i++)
            {
                //if (this.Contains(items[i]))
                this.Remove(items[i]);//省去一次遍历
                this.Add(items[i]);
            }
            return this;
        }
        public ListEx<T> Concat(params ListEx<T>[] arrs)
        {
            var narr = new ListEx<T>();
            narr.AddRange(this);
            for (var i = 0; i < arrs.Length; i++)
                narr.AddRange(arrs[i]);
            return narr;
        }
        public string Join(string separator = "")
        {
            return String.Join(separator, this);
        }
        public ListEx<T> Filter(Func<T, bool> filterFunc)
        {
            var newArr = new ListEx<T>();
            for (int i = 0; i < Length; i++)
            {
                var item = this[i];
                if (filterFunc(item))
                    newArr.Push(item);
            }
            return newArr;
        }
        public T Pop()
        {
            if (this.Count <= 0)
            {
                return default(T);
            }
            T t = this[this.Count - 1];
            this.RemoveAt(this.Count - 1);
            return t;
        }
        public T Shift()
        {
            T t = this[0];
            this.RemoveAt(0);
            return t;
        }
        public ListEx<T> Slice(int start, int end)
        {
            var narr = new ListEx<T>();
            for (var i = start; i < end; i++)
                narr.Add(this[i]);
            return narr;
        }
        public ListEx<T> Slice(int start)
        {
            var narr = new ListEx<T>();
            for (var i = start; i < this.Count; i++)
                narr.Add(this[i]);
            return narr;
        }
        public ListEx<T> Slice()
        {
            return this.Clone();
        }

        public ListEx<T> Splice(int start, int removes, params T[] addItems)
        {
            ListEx<T> rarr = null;
            if (removes > 0)
            {
                rarr = new ListEx<T>();
                for (var i = start; i < start + removes; i++)
                {
                    rarr.Push(this[i]);
                }
                this.RemoveRange(start, removes);
            }
            this.InsertRange(start, addItems);
            return rarr;
        }

        public int Unshift(params T[] addItems)
        {
            this.InsertRange(0, addItems);
            return this.Count;
        }

        public ListEx<T> Clone()
        {
            var narr = new ListEx<T>();
            narr.AddRange(this);
            return narr;
        }

        public ListEx<T> Reset(int count)
        {
            this.Clear();
            for (var i = 0; i < count; i++)
                this.Add(default(T));
            return this;
        }
        public K[] Map<K>(Func<T, int, K> func)
        {
            var marr = new K[this.Count];
            for (var i = 0; i < this.Count; i++)
            {
                marr[i] = func(this[i], i);
            }
            return marr;
        }
        public bool Has(T value)
        {
            return this.IndexOf(value) >= 0;
        }

        public void Delete(T value)
        {
            this.Remove(value);
        }



        public void SpliteTwoPart(int start, out ListEx<T> firstPart, out ListEx<T> secPart)
        {
            if (start > this.Length)
                start = this.Length;
            firstPart = this.Slice(0, start);
            if (start == this.Length)
                secPart = null;
            else
                secPart = this.Slice(start);
        }
        public bool Some(Func<T, bool> callbackFn)
        {
            foreach (var item in this)
            {
                if (callbackFn(item))
                {
                    return true;
                }
            }
            return false;
        }
    }

 
}
